#include "annex_b.h"



static inline u8 annexb_startcode_len(u8 *buf4)
{
	if (buf4 == NULL)
		return 0;
	if (buf4[0] == 0 && buf4[1] == 0)
	{
		if (buf4[2] == 1)
		{
			return 3;
		}
		else if (buf4[2] == 0)
		{
			if (buf4[3] == 1)
			{
				return 4;
			}
		}
	}
	return 0;
}

enum {
	annexb_sm_find,
	annexb_sm_callback,
};
static const u8 annexb_startcode3[3] = { 0,0,1 };
static const u8 annexb_startcode4[4] = { 0,0,0,1 };
typedef struct annexb_sm_st
{
	u8 state;
	s264buf_t nalu_buf, sc_buf;
}annexb_sm_t;

/// @brief annexb解析状态机初始化
/// @param sm annexb_sm_t变量地址
/// @return -1:参数错误 0:成功 -2:nalu_buf 初始化失败 -3:sc_buf 初始化失败
static inline i8 annexb_sm_init(annexb_sm_t *sm)
{
	if (sm == NULL)
		return-1;
	s264_memset(sm, 0, sizeof(annexb_sm_t));
	i8 nalu = s264buf_init(&(sm->nalu_buf), 255);
	if (nalu != 0)
		return -2;
	i8 sc = s264buf_init(&(sm->sc_buf), 255);
	if (sc != 0)
	{
		s264buf_deinit(&(sm->nalu_buf));
		return -3;
	}
	return 0;
}
/// @brief annexb解析状态机运行
/// @param c 字符
/// @param sm annexb_sm_t地址
/// @return 
static inline i8 annexb_sm_handle(u8 c, annexb_sm_t *sm)
{
	if (sm == NULL)
		return -1;
	i8 ret = 0;
	if (sm->state == annexb_sm_callback) // 转出状态机后在外部执行回调 完毕再次进入状态机处理 =>将数据清空 并 记录startcode数据
	{
		// clear old data
		s264buf_clear(&(sm->nalu_buf));
		// save startcode0
		ret = s264buf_append(&(sm->nalu_buf), sm->sc_buf.data, sm->sc_buf.len);
		if (ret)
			return -2;
		// clear sc data
		s264buf_clear(&(sm->sc_buf));
		sm->state = annexb_sm_find;
	}
	if (c == 0 || c == 1) 
	{
		ret = s264buf_append(&(sm->sc_buf), &c, 1);
		if (ret)
			return -3;
		if (
			(sm->sc_buf.len == 3 && s264_memcmp(sm->sc_buf.data, annexb_startcode3, sm->sc_buf.len) == 0) ||
			(sm->sc_buf.len == 4 && s264_memcmp(sm->sc_buf.data, annexb_startcode4, sm->sc_buf.len) == 0)
			)
		{
			if (sm->nalu_buf.len > 0) //找到下一状态机跳出状态机
				sm->state = annexb_sm_callback;
		}
	}
	else
	{
		// nalu数据收集
		sm->state = annexb_sm_find;
		if (sm->sc_buf.len != 0) // startcode || 00 || 01 数据收集
		{
			ret = s264buf_append(&(sm->nalu_buf), sm->sc_buf.data, sm->sc_buf.len);
			if (ret)
				return -4;
			s264buf_clear(&(sm->sc_buf));
		}
		// 非 01 00 数据收集
		ret = s264buf_append(&(sm->nalu_buf), &c, 1);
		if (ret)
			return -4;
	}
	return ret;
}
/// @brief annexb解析状态机销毁
/// @param sm annexb_sm_t地址
static inline void annexb_sm_deinit(annexb_sm_t *sm)
{
	if (sm == NULL)
		return;
	s264buf_deinit(&(sm->nalu_buf));
	s264buf_deinit(&(sm->sc_buf));
	sm->state = annexb_sm_find;
}

#define annexb_buf_len (3 * 4 * 100)

/// @brief 从文件描述符解码annexb中nalu
/// @param fp fopen成功的FILE *变量
/// @param userdata 用户自定义数据
/// @param callback 回调函数
void annexb_parse_fp(FILE *fp, void *userdata, annexb_parse_cb_impl callback)
{
	if (fp == NULL && callback != NULL)
		return;
	annexb_sm_t sm;
	if (annexb_sm_init(&sm))
		return;
	
	u8 buf[annexb_buf_len] = { 0 };
	u64 n = 0;
	while ((n = fread(buf, sizeof(u8), annexb_buf_len, fp)) != 0)
	{
		u8 *readbuf = buf;
		u64 readn = n;
		u8 again = 0;
		do
		{
			for (size_t i = 0; i < n; i++)
			{
				i8 handle_ret = annexb_sm_handle(readbuf[i], &sm);
				if (sm.state == annexb_sm_callback)
				{
					nalu_t nalu = (nalu_t){
						.buf = sm.nalu_buf.data,
						.buf_len = sm.nalu_buf.len,
						.startcode_len = sm.nalu_buf.data[2] == 0 && sm.nalu_buf.data[3] == 1 ? 4 :3,
					};
					callback(fp, &nalu, userdata);
				}
			}
			if (again == 0)
			{
				if (n < annexb_buf_len)
				{
					readbuf = (u8 *) annexb_startcode3;
					n = sizeof(annexb_startcode3);
					again = 1;
				}
			}
			else
			{
				again = 0;
			}
		} while (again);
	}

	annexb_sm_deinit(&sm);
}

